
#include"InterfGraph.hpp"
#include"MachineSpec.hpp"
#include"Operation.hpp"
#include"Operand.hpp"
#include"Value.hpp"

bool  InterfGraph::PseudoReg::is_macro_symbol()
{
	if(pseudo_reg <= INPUT_SP && pseudo_reg >= P0)
		return true;	
	else
		return false;
}

void InterfGraph::add_interference(int x, int y)
{
	adjtable[x].add_interf(y);
	adjtable[y].add_interf(x);	
}

void InterfGraph::build_interference(int pseudo_reg, std::set<int> const & interferences)
{
	for(std::set<int>::iterator it = interferences.begin(); it != interferences.end(); it++)
	{
		add_interference(pseudo_reg, (*it));	
	}	
}

void InterfGraph::add_use(Instruction * instr, int id)
{
	std::map<int, PseudoReg>::iterator it = adjtable.find(id) ;
	//because , skan the region in the first order , 
	//so the before symbol's use is add , symbol's def had been added 
	assert(it != adjtable.end());
	it->second.add_use(instr);
}

void InterfGraph::add_def(Instruction* instr, int id)
{
	std::map<int, PseudoReg>::iterator it = adjtable.find(id);
	if(it == adjtable.end())
	{
		adjtable[id].set_symbol_id(id);
		adjtable[id].add_def(instr);	
	}
	else
	{
		it->second.add_def(instr);
	}
}

void InterfGraph::build_vector_associate_info(const SimdOperand * opd)
{
	std::vector<int> const & ids = opd->get_ids();
	if(vector_associate_info.find(ids[0]) == vector_associate_info.end())
	{	
		vector_associate_info[0] = new int[8];
		for(int i = 0; i < 8; i++)
		{
			vector_associate_info[ids[0]][i] = ids[i];
		}
	}
	else
	{ 	//sanity check 
		for(int i = 0; i < 8; i++)
		{
			assert(vector_associate_info[ids[0]][i] ==  ids[i]);
		}
	}
}

void InterfGraph::free_vector_associate_info()
{
	for(std::map<int, int *>::iterator it = vector_associate_info.begin();  it != vector_associate_info.end(); it++)
	{
		delete[](it->second);
		it->second = NULL;
	}
}

RegMask InterfGraph::get_prevent_mask(int id)
{
	RegMask  reg_mask;
	const std::set<int> & interfs = adjtable[id].interfs;
	for(std::set<int>::iterator it = interfs.begin(); it != interfs.end(); it++)
	{
		int t  = (*it);
		if(adjtable[t].is_assigned())
		{
			enum TargetInfo::PhysicalRegister physical_reg = adjtable[t].physical_register;
			reg_mask.add_reg(physical_reg);
		}
	}
	return reg_mask;
}

void InterfGraph::assign_physical_register(int id, enum TargetInfo::PhysicalRegister  physical_register)
{
	PseudoReg & pseudo_reg = adjtable[id];
	pseudo_reg.physical_register = physical_register;
	//assign the defs;
	for(int i = 0; i < pseudo_reg.defs.size(); i++)
	{
		pseudo_reg.defs[i]->dest_assign_physical_register(id, physical_register);
	}
	//assign the uses;
	for(int i = 0; i < pseudo_reg.uses.size(); i++)
	{
		pseudo_reg.uses[i]->src_assign_physical_register(id, physical_register);
	}
}

void InterfGraph::color_register()
{
	//first color the macro_register			
	for(int i = P0; i <= INPUT_SP; i++)
	{
		TargetInfo::PhysicalRegister reg = M_get_macro_physical_register((enum MACRO_ID) i);
		assign_physical_register(i, reg);
	}
	//process the vector symbol register
	for(std::map<int, int*>::iterator it = vector_associate_info.begin(); it != vector_associate_info.end(); it++)
	{
		int id = it->first; 	
		RegMask x  = get_prevent_mask(id);
		const std::vector<int>& regs = x.get_allowed_simd_reg();
		assert(regs.size() == 8 && "TODO take account the spill simd register");
		for(int i = 0; i < 8; i++)
		{
			assign_physical_register(it->second[i], (enum TargetInfo::PhysicalRegister)regs[i]);
		}
	}
	//process the caller save
}

